﻿using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

using GoblinXNA;
using GoblinXNA.SceneGraph;
using GoblinXNA.Graphics;
using GoblinXNA.Graphics.ParticleEffects;
using GoblinXNA.Device.Capture;
using GoblinXNA.Device.Vision.Marker;
using GoblinXNA.Device.Generic;
using GoblinXNA.Device;
using Model = GoblinXNA.Graphics.Model;
using GoblinXNA.Graphics.Geometry;
using GoblinXNA.Physics;
using GoblinXNA.Physics.Newton1;
using GoblinXNA.Helpers;

using NewtonDynamics;

namespace AugmentedRealityTeam
{
    public class WallCreator
    {
        public GeometryNode[] wallNode;
        public TransformNode[] wallTransNode;
        public Material[] wallMaterial;
        public int wallindex = -1;
        public int iniWallSize = 10;

        public GeometryNode realgNode;
        Scene scene;
        MarkerNode gMarkerNode;
        float scaleObjRatio = 5.0f;

        public NewtonPhysics.CollisionPair[] carWallCollisionPairs;
        public RaceCar racecar;


        public WallCreator(GeometryNode realGroundNode, Scene sce, MarkerNode groundMarkerNode, RaceCar rcar)
        {
            realgNode = realGroundNode;
            scene = sce;
            gMarkerNode = groundMarkerNode;

            wallNode = new GeometryNode[100];
            wallMaterial = new Material[100];
            wallTransNode = new TransformNode[100];
            carWallCollisionPairs = new NewtonPhysics.CollisionPair[100];

         

            racecar = rcar;
        }

        private static Newton.NewtonHinge groundWall = delegate(IntPtr hingeJoint,
           ref Newton.NewtonHingeSliderUpdateDesc desc)
        {
            float angle;

            // set the angle limit to 90 degrees for the hinge
            float angleLimit = 0;

            angle = Newton.NewtonHingeGetJointAngle(hingeJoint);

            // if the hinge's angle is greater than the limit, then stop it
            if (angle > ((angleLimit / 180.0f) * MathHelper.Pi))
            {
                desc.m_Accel = Newton.NewtonHingeCalculateStopAlpha(hingeJoint, ref desc,
                    (angleLimit / 180.0f) * MathHelper.Pi);
                return 1;
            }
            // if the hinge's angle is greater than the limit on the reverse side, then also stop it
            else if (angle < ((-angleLimit / 180.0f) * MathHelper.Pi))
            {
                desc.m_Accel = Newton.NewtonHingeCalculateStopAlpha(hingeJoint, ref desc,
                    (-angleLimit / 180.0f) * MathHelper.Pi);
                return 1;
            }

            // no action need it if the joint angle is with the limits
            return 0;
        };



        ////create a wall that all ways stay together with the ground
        //public void placeWallOnGround(float TranslationX, float TranslationY, float sizeX, float sizeY, float sizeZ)
        //{
        //    sizeX = sizeX * scaleObjRatio;
        //    sizeY = sizeY * scaleObjRatio;
        //    sizeZ = sizeZ * scaleObjRatio;
        //    TranslationX = TranslationX * scaleObjRatio;
        //    TranslationY = TranslationY * scaleObjRatio;
        //    Vector3 location = new Vector3((sizeX - iniWallSize) / 2 + TranslationX, (sizeY - iniWallSize) / 2 + TranslationY, -sizeZ / 2);

        //    {
        //        float TranslationXTemp = (sizeX - iniWallSize) / 2 + TranslationX;
        //        float TranslationYTemp = (sizeY - iniWallSize) / 2 + TranslationY;

        //        //     wallNode[wallindex] = new GeometryNode("wall" + wallindex);
        //        //    wallNode[wallindex].Model = new Box(sizeX, sizeY, sizeZ);

        //        // Make the sphere models interactable, which means that they
        //        // participate in the physical simulation
        //        wallNode[wallindex].Physics.Interactable = true;
        //        wallNode[wallindex].Physics.Collidable = true;
        //        wallNode[wallindex].Physics.Shape = ShapeType.Box;
        //        wallNode[wallindex].Physics.Mass = 2f;
        //        wallNode[wallindex].AddToPhysicsEngine = true;

        //        // Make this box model cast and receive shadows
        //        wallNode[wallindex].Model.CastShadows = true;
        //        wallNode[wallindex].Model.ReceiveShadows = true;

        //        // Create a material to apply to the box model
        //        wallMaterial[wallindex] = new Material();
        //        wallMaterial[wallindex].Diffuse = Color.Green.ToVector4();
        //        wallMaterial[wallindex].Specular = Color.White.ToVector4();
        //        wallMaterial[wallindex].SpecularPower = 10;

        //        wallNode[wallindex].Material = wallMaterial[wallindex];

        //        //           wallTransNode[wallindex] = new TransformNode("wallTransNode" + wallindex);
        //        wallTransNode[wallindex].Translation = new Vector3(TranslationXTemp, TranslationYTemp, 5f);

        //       // wallCollisionPairs[wallindex]

        //        // Add this box model node to the ground marker node            
        //        realgNode.AddChild(wallTransNode[wallindex]);
        //        //     wallTransNode[wallindex].AddChild(wallNode[wallindex]);                

        //        Vector3 pivot = location;
        //        Vector3 pin;
        //        if (sizeX < sizeY)
        //        {
        //            pin = Vector3.UnitX;
        //            pivot.X += sizeX * 0.5f;
        //        }
        //        else
        //        {
        //            pin = Vector3.UnitY;
        //            pivot.Y -= sizeY * 0.5f;
        //        }

        //        HingeJoint joint = new HingeJoint(pivot, pin);
        //        joint.NewtonHingeCallback = groundWall;
        //        ((NewtonPhysics)scene.PhysicsEngine).CreateJoint(wallNode[wallindex].Physics, realgNode.Physics, joint);

        //    }
        //}

        public void createWallOnGround(float TranslationX, float TranslationY, float sizeX, float sizeY, float sizeZ)
        {
            sizeX = sizeX * scaleObjRatio;
            sizeY = sizeY * scaleObjRatio;
            sizeZ = sizeZ * scaleObjRatio;
            TranslationX = TranslationX * scaleObjRatio;
            TranslationY = TranslationY * scaleObjRatio;
            Vector3 location = new Vector3((sizeX - iniWallSize) / 2 + TranslationX, (sizeY - iniWallSize) / 2 + TranslationY, -sizeZ / 2);

            {
                float TranslationXTemp = (sizeX - iniWallSize) / 2 + TranslationX;
                float TranslationYTemp = (sizeY - iniWallSize) / 2 + TranslationY;

                wallindex++;
                wallNode[wallindex] = new GeometryNode("wall" + wallindex);
                wallNode[wallindex].Model = new Box(sizeX, sizeY, sizeZ);

                // Make the sphere models interactable, which means that they
                // participate in the physical simulation
                wallNode[wallindex].Physics.Interactable = true;
                wallNode[wallindex].Physics.Collidable = true;
                wallNode[wallindex].Physics.Shape = ShapeType.Box;
                wallNode[wallindex].Physics.Mass = 2f;
                wallNode[wallindex].AddToPhysicsEngine = true;

                // Make this box model cast and receive shadows
                wallNode[wallindex].Model.CastShadows = true;
                wallNode[wallindex].Model.ReceiveShadows = true;

                // Create a material to apply to the box model
                wallMaterial[wallindex] = new Material();
                wallMaterial[wallindex].Diffuse = Color.Green.ToVector4();
                wallMaterial[wallindex].Specular = Color.White.ToVector4();
                wallMaterial[wallindex].SpecularPower = 10;

                wallNode[wallindex].Material = wallMaterial[wallindex];

                wallTransNode[wallindex] = new TransformNode("wallTransNode" + wallindex);
                wallTransNode[wallindex].Translation = new Vector3(TranslationXTemp, TranslationYTemp, 5f);

                // Add this box model node to the ground marker node            
                realgNode.AddChild(wallTransNode[wallindex]);
                wallTransNode[wallindex].AddChild(wallNode[wallindex]);                

                Vector3 pivot = location;
                Vector3 pin;
                if (sizeX < sizeY)
                {
                    pin = Vector3.UnitX;
                    pivot.X += sizeX * 0.5f;
                }
                else
                {
                    pin = Vector3.UnitY;
                    pivot.Y -= sizeY * 0.5f;
                }

                HingeJoint joint = new HingeJoint(pivot, pin);
                joint.NewtonHingeCallback = groundWall;
                ((NewtonPhysics)scene.PhysicsEngine).CreateJoint(wallNode[wallindex].Physics, realgNode.Physics, joint);              
            }
        }
    }
}
